Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make AsRef and AsMut reflexive #39397

Closed
wants to merge 1 commit into from

Conversation

clarfonthey
Copy link
Contributor

This would probably require a crater run.

I found it weird that T didn't implement AsRef and AsMut, considering how the conversions are trivial.

@rust-highfive
Copy link
Collaborator

r? @brson

(rust_highfive has picked a reviewer for you, use r? to override)

@Stebalien
Copy link
Contributor

Unfortunately, this is why: https://travis-ci.org/rust-lang/rust/jobs/196373035#L384

error[E0119]: conflicting implementations of trait `convert::AsRef<&_>` for type `&_`:
   --> /checkout/src/libcore/convert.rs:237:1
    |
229 |   impl<'a, T: ?Sized> AsRef<T> for T {
    |  _- starting here...
230 | |     fn as_ref(&self) -> &T {
231 | |         self
232 | |     }
233 | | }
    | |_- ...ending here: first implementation here
...
237 |   impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    |  _^ starting here...
238 | |     fn as_ref(&self) -> &U {
239 | |         <T as AsRef<U>>::as_ref(*self)
240 | |     }
241 | | }
    | |_^ ...ending here: conflicting implementation for `&_`

error[E0119]: conflicting implementations of trait `convert::AsRef<&mut _>` for type `&mut _`:
   --> /checkout/src/libcore/convert.rs:245:1
    |
229 |   impl<'a, T: ?Sized> AsRef<T> for T {
    |  _- starting here...
230 | |     fn as_ref(&self) -> &T {
231 | |         self
232 | |     }
233 | | }
    | |_- ...ending here: first implementation here
...
245 |   impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    |  _^ starting here...
246 | |     fn as_ref(&self) -> &U {
247 | |         <T as AsRef<U>>::as_ref(*self)
248 | |     }
249 | | }
    | |_^ ...ending here: conflicting implementation for `&mut _`

error[E0119]: conflicting implementations of trait `convert::AsMut<&mut _>` for type `&mut _`:
   --> /checkout/src/libcore/convert.rs:269:1
    |
261 |   impl<'a, T: ?Sized> AsMut<T> for T {
    |  _- starting here...
262 | |     fn as_mut(&mut self) -> &mut T {
263 | |         self
264 | |     }
265 | | }
    | |_- ...ending here: first implementation here
...
269 |   impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    |  _^ starting here...
270 | |     fn as_mut(&mut self) -> &mut U {
271 | |         (*self).as_mut()
272 | |     }
273 | | }
    | |_^ ...ending here: conflicting implementation for `&mut _`

error: aborting due to 3 previous errors

@brson
Copy link
Contributor

brson commented Feb 1, 2017

Seems problematic per @Stebalien.

@Ixrec
Copy link
Contributor

Ixrec commented Feb 1, 2017

I remember someone asking why we don't have this impl in one of the IRC channels the other day and we also guessed it would conflict with precisely that existing implementation.

Is this something that might become possible after specialization stabilizes?

@clarfonthey
Copy link
Contributor Author

Sometimes I wish that there were a trait similar to:

impl<'a, T> Ref for &'a T {}
impl<'a, T> Ref for &'a mut T {}

Such that I could provide !Ref bounds to these impls and fix a lot of things. Because imho it's kind of silly that we have to manually implement this for specific types.

@sfackler
Copy link
Member

sfackler commented Feb 1, 2017

Should this be closed?

@leoyvens
Copy link
Contributor

leoyvens commented Feb 1, 2017

A great read on why this can't be done and maybe one day we will be able to do it:
http://smallcultfollowing.com/babysteps/blog/2016/10/24/supporting-blanket-impls-in-specialization/

@clarfonthey
Copy link
Contributor Author

I'll close this for now and re-open when impl specialisation hits.

@clarfonthey clarfonthey closed this Feb 1, 2017
@colin-kiegel
Copy link

Can't the conflicting implementations above be removed?

I guess specialization is only necessary to prevent downstream crates from conflicting with the new generic implementation, right??

Link: tracking issue for specialization (RFC 1210).


I would like to make Option::<T>::as_ref(&self) -> Option<&T> generic such that it becomes Option::<T>::as_ref(&self) -> Option<&U> where T: AsRef<U>. But that would require AsRef to be reflexive.

Here is my use case :-)

let opt: &Option<String>;
// ...
let result: &str = opt // &Option<String>
    .as_ref() // Option<&String>
    .map(|x| x.as_ref()) // Option<&str> -- this step could be omitted
    .unwrap_or(".. nothing there"); // &str

@leoyvens
Copy link
Contributor

@colin-kiegel To be clear we need more than specialization as it exists to make this work, so stabilizing specialization and closing that issue is not enough. If the other impls are removed then we lose functionality because the impls intersect but one is not contained in the other.

@clarfonthey clarfonthey deleted the as_ref_reflexive branch April 15, 2018 20:31
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Oct 3, 2022
…riplett

docs: Improve AsRef / AsMut docs on blanket impls

There are several issues with the current state of `AsRef` and `AsMut` as [discussed here on IRLO](https://internals.rust-lang.org/t/semantics-of-asref/17016). See also rust-lang#39397, rust-lang#45742, rust-lang#73390, rust-lang#98905, and the FIXMEs [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L509-L515) and [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L530-L536). These issues are difficult to fix. This PR aims to update the documentation to better reflect the status-quo and to give advice on how `AsRef` and `AsMut` should be used.

In particular:

- Explicitly mention that `AsRef` and `AsMut` do not auto-dereference generally for all dereferencable types (but only if inner type is a shared and/or mutable reference)
- Give advice to not use `AsRef` or `AsMut` for the sole purpose of dereferencing
- Suggest providing a transitive `AsRef` or `AsMut` implementation for types which implement `Deref`
- Add new section "Reflexivity" in documentation comments for `AsRef` and `AsMut`
- Provide better example for `AsMut`
- Added heading "Relation to `Borrow`" in `AsRef`'s docs to improve structure
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Oct 3, 2022
…riplett

docs: Improve AsRef / AsMut docs on blanket impls

There are several issues with the current state of `AsRef` and `AsMut` as [discussed here on IRLO](https://internals.rust-lang.org/t/semantics-of-asref/17016). See also rust-lang#39397, rust-lang#45742, rust-lang#73390, rust-lang#98905, and the FIXMEs [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L509-L515) and [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L530-L536). These issues are difficult to fix. This PR aims to update the documentation to better reflect the status-quo and to give advice on how `AsRef` and `AsMut` should be used.

In particular:

- Explicitly mention that `AsRef` and `AsMut` do not auto-dereference generally for all dereferencable types (but only if inner type is a shared and/or mutable reference)
- Give advice to not use `AsRef` or `AsMut` for the sole purpose of dereferencing
- Suggest providing a transitive `AsRef` or `AsMut` implementation for types which implement `Deref`
- Add new section "Reflexivity" in documentation comments for `AsRef` and `AsMut`
- Provide better example for `AsMut`
- Added heading "Relation to `Borrow`" in `AsRef`'s docs to improve structure
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Oct 3, 2022
…riplett

docs: Improve AsRef / AsMut docs on blanket impls

There are several issues with the current state of `AsRef` and `AsMut` as [discussed here on IRLO](https://internals.rust-lang.org/t/semantics-of-asref/17016). See also rust-lang#39397, rust-lang#45742, rust-lang#73390, rust-lang#98905, and the FIXMEs [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L509-L515) and [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L530-L536). These issues are difficult to fix. This PR aims to update the documentation to better reflect the status-quo and to give advice on how `AsRef` and `AsMut` should be used.

In particular:

- Explicitly mention that `AsRef` and `AsMut` do not auto-dereference generally for all dereferencable types (but only if inner type is a shared and/or mutable reference)
- Give advice to not use `AsRef` or `AsMut` for the sole purpose of dereferencing
- Suggest providing a transitive `AsRef` or `AsMut` implementation for types which implement `Deref`
- Add new section "Reflexivity" in documentation comments for `AsRef` and `AsMut`
- Provide better example for `AsMut`
- Added heading "Relation to `Borrow`" in `AsRef`'s docs to improve structure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants